﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace CalendarCloudSync.Providers.Exchange
{
    public class ExchangeProvider
    {
        public ExchangeProvider(string username, string password, string domain, string url)
        {
            this.UserName = username;
            this.Password = password;
            this.Domain = domain;
            this.URL = url;

            this.esb = new ExchangeServiceBinding();
            esb.Credentials = new NetworkCredential(this.UserName, this.Password, this.Domain);
            esb.Url = this.URL;

        }

        public string UserName { get; set; }
        public string Password { get; set; }
        public string Domain { get; set; }
        public string URL { get; set; }

        private ExchangeServiceBinding esb { get; set; }

        // -----------------------------------------------------------------
        // GetCalendarViewForToday
        // Returns a calendar view for today.
        // -----------------------------------------------------------------

        public static CalendarViewType GetCalendarViewForToday()
        {
            return GetCalendarViewForDay(
                    DateTime.Now.Year,
                    DateTime.Now.Month,
                    DateTime.Now.Day
                    );
        }

        // -----------------------------------------------------------------
        // GetCalendarViewForDay
        // Returns a calendar view for a given day.
        // -----------------------------------------------------------------
        public static CalendarViewType GetCalendarViewForDay(int iYear, int iMonth, int iDay)
        {
            DateTime dtToday12AM = new DateTime(iYear, iMonth, iDay, 0, 0, 0, DateTimeKind.Local);
            CalendarViewType calendarView = new CalendarViewType();
            calendarView.StartDate = dtToday12AM;
            calendarView.EndDate = calendarView.StartDate.AddDays(1);
            calendarView.MaxEntriesReturned = 99;
            calendarView.MaxEntriesReturnedSpecified = true;
            return calendarView;
        }

        // -----------------------------------------------------------------
        // GetCalendarViewForWeek
        // Returns a calendar view for the week of a given date.
        // -----------------------------------------------------------------
        private CalendarViewType GetCalendarViewForWeek(int iYear, int iMonth, int iDay)
        {
            // create a date time instance which represents the day at 12:00:00am
            DateTime workDateTime = new DateTime(iYear, iMonth, iDay, 0, 0, 0, DateTimeKind.Local);
            DateTime FirstDOW = GetFirstDOW(workDateTime);
            DateTime LastDOW = GetLastDOW(workDateTime);

            CalendarViewType calendarView = new CalendarViewType();
            calendarView.StartDate = FirstDOW;
            calendarView.EndDate = LastDOW;
            calendarView.MaxEntriesReturned = 99;
            // Don’t forget to set the specified flag
            calendarView.MaxEntriesReturnedSpecified = true;

            return calendarView;
        }

        // -----------------------------------------------------------------------
        // GetFirstDOW
        // Returns a the first day of the week for a given date.
        // In this routine, Sunday is considered to be the first day of the
        // However, the day considered to be the first day of the week may vary depending
        // upon culture. Cultural specific coding is not covered in this sample.
        // -----------------------------------------------------------------------
        public static DateTime GetFirstDOW(DateTime dtDate)
        {
            DateTime FirstDayofWeek = dtDate;

            //CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek
            switch (dtDate.DayOfWeek)
            {
                case DayOfWeek.Sunday:
                    FirstDayofWeek = dtDate;
                    break;
                case DayOfWeek.Monday:
                    FirstDayofWeek = dtDate.AddDays(-1);
                    break;
                case DayOfWeek.Tuesday:
                    FirstDayofWeek = dtDate.AddDays(-2);
                    break;
                case DayOfWeek.Wednesday:
                    FirstDayofWeek = dtDate.AddDays(-3);
                    break;
                case DayOfWeek.Thursday:
                    FirstDayofWeek = dtDate.AddDays(-4);
                    break;
                case DayOfWeek.Friday:
                    FirstDayofWeek = dtDate.AddDays(-5);
                    break;
                case DayOfWeek.Saturday:
                    FirstDayofWeek = dtDate.AddDays(-6);
                    break;
            }
            return FirstDayofWeek;
        }

        // -----------------------------------------------------------------------
        // GetLastDOW
        // Returns a the last day of the week for a given date.
        // In this routine, Sunday is considered to be the last day of the
        // However, the day considered to be the last day of the week may vary depending
        // upon culture. Cultural specific coding is not covered in this sample.
        // -----------------------------------------------------------------------
        public static DateTime GetLastDOW(DateTime dtDate)
        {
            DateTime LastDayofWeek = dtDate;

            //CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek
            switch (dtDate.DayOfWeek)
            {
                case DayOfWeek.Sunday:
                    LastDayofWeek = dtDate.AddDays(6);
                    break;
                case DayOfWeek.Monday:
                    LastDayofWeek = dtDate.AddDays(5);
                    break;
                case DayOfWeek.Tuesday:
                    LastDayofWeek = dtDate.AddDays(4);
                    break;
                case DayOfWeek.Wednesday:
                    LastDayofWeek = dtDate.AddDays(3);
                    break;
                case DayOfWeek.Thursday:
                    LastDayofWeek = dtDate.AddDays(2);
                    break;
                case DayOfWeek.Friday:
                    LastDayofWeek = dtDate.AddDays(1);
                    break;
                case DayOfWeek.Saturday:
                    LastDayofWeek = dtDate;
                    break;
            }
            return LastDayofWeek;
        }

        // -----------------------------------------------------------------------
        // GetCalendarViewForMonth
        // Returns a calendar view for a given year/month
        // -----------------------------------------------------------------------
        public static CalendarViewType GetCalendarViewForMonth(int iYear, int iMonth)
        {
            DateTime dtLastDayOfMonth = new DateTime(
                    iYear,
                    iMonth,
                    DateTime.DaysInMonth(iYear, iMonth)
                    );

            DateTime dtStart = new DateTime(
                    iYear, iMonth, 1,
                    0, 0, 0,
                    DateTimeKind.Local
                    );

            CalendarViewType calendarView = new CalendarViewType();
            calendarView.StartDate = dtStart;
            calendarView.EndDate = dtLastDayOfMonth;
            calendarView.MaxEntriesReturned = 100;
            calendarView.MaxEntriesReturnedSpecified = true;
            return calendarView;
        }


        public void GetCalendarItemsForWeek(int iYear, int iMonth, int iDay)
        {
            CalendarViewType cvtView = GetCalendarViewForWeek(iYear, iMonth, iDay);
            GetCalendarItems(cvtView);
        }

        //----------------------------------------------------------------------
        // GetCalendarItems
        // Returns a list of calendar items as text based on a calendar view.
        //----------------------------------------------------------------------
        private void GetCalendarItems(CalendarViewType calendarView)
        {

            string sLine = "";
            string sLines = "";

            FindItemType findItemRequest = new FindItemType();

            findItemRequest.ParentFolderIds = new DistinguishedFolderIdType[] { new DistinguishedFolderIdType() };
            ((DistinguishedFolderIdType)findItemRequest.ParentFolderIds[0]).Id =
                DistinguishedFolderIdNameType.calendar;

            findItemRequest.Traversal = ItemQueryTraversalType.Shallow;

            ItemResponseShapeType itemShapeDefinition = new ItemResponseShapeType();
            itemShapeDefinition.BaseShape = DefaultShapeNamesType.AllProperties;

            findItemRequest.Item = calendarView;
            findItemRequest.ItemShape = itemShapeDefinition;

            // Do the EWS Call...
            FindItemResponseType findItemResponse = this.esb.FindItem(findItemRequest);

            // Check for errors?
            if (findItemResponse.ResponseMessages.Items[0].ResponseClass !=
            ResponseClassType.Success)
            {

                throw new Exception(String.Format("Error:\r\n{0}\r\n{1}",
                    findItemResponse.ResponseMessages.Items[0].ResponseCode,
                    findItemResponse.ResponseMessages.Items[0].MessageText));
            }


            FindItemResponseMessageType findItemResponseMessage =
                (FindItemResponseMessageType)findItemResponse.
                    ResponseMessages.Items[0];
            ArrayOfRealItemsType findItemResponseItems = (ArrayOfRealItemsType)findItemResponseMessage.RootFolder.Item;

            //sLine = string.Format(
            //    "There are {0} appointments between \r\n\t{1} on {2} and\r\n" +
            //    "\t{3} on {4}\r\n------------------------------\r\n",
            //    findItemResponseMessage.RootFolder.TotalItemsInView,
            //    calendarView.StartDate.ToLongTimeString(),
            //    calendarView.StartDate.ToLongDateString(),
            //    calendarView.EndDate.ToLongTimeString(),
            //    calendarView.EndDate.ToLongDateString());
            //Console.WriteLine(sLine);
            //sLines = sLine;

            for (int x = 0; x < findItemResponseMessage.RootFolder.TotalItemsInView; x++)
            {

                CalendarItemType currentCalendarItem = (CalendarItemType)findItemResponseItems.Items[x];

                Console.WriteLine(currentCalendarItem.Subject);

                // Exchange stores all calendaring data in UTC time. So, convert to local
                // time so the person looking at the dates dont have to do the time math.
                sLine = "    Starts at: " +
                    currentCalendarItem.Start.ToLocalTime().ToShortTimeString() +
                    " on " + currentCalendarItem.Start.ToLocalTime().DayOfWeek +
                    "  (" + currentCalendarItem.Start.ToString() + ")";
                Console.WriteLine(sLine);
                sLines += sLine + "\r\n";
                sLine = "    Ends at: " +
                    currentCalendarItem.End.ToLocalTime().ToShortTimeString() +
                    " on " + currentCalendarItem.End.ToLocalTime().DayOfWeek +
                    "  (" + currentCalendarItem.End.ToString() + ")";
                Console.WriteLine(sLine);
                sLines += sLine + "\r\n";

                //Console.WriteLine("    RecurrenceId: " + currentCalendarItem.RecurrenceId);
                Console.WriteLine("    Id: " + currentCalendarItem.ItemId.Id);
                //Console.WriteLine("    ChangeKey: " + currentCalendarItem.ItemId.ChangeKey);
                //Console.WriteLine("    Organizer Name: " + currentCalendarItem.Organizer.Item.Name);
                //Console.WriteLine("    IsRecurring: " + currentCalendarItem.IsRecurring.ToString());
                Console.WriteLine("    IsMeeting: " + currentCalendarItem.IsMeeting.ToString());
                //Console.WriteLine("    OriginalStart: " + currentCalendarItem.OriginalStart.ToString());
                //Console.WriteLine("    HasAttachments: " + currentCalendarItem.HasAttachments.ToString());
                //Console.WriteLine("    Attachments: ");

                //sLines += "    RecurrenceId: " + currentCalendarItem.RecurrenceId + "\r\n";
                //sLines += "    Id: " + currentCalendarItem.ItemId.Id + "\r\n";
                //sLines += "    ChangeKey: " + currentCalendarItem.ItemId.ChangeKey + "\r\n";
                //sLines += "    Organizer Name: " + currentCalendarItem.Organizer.Item.Name + "\r\n";
                //sLines += "    IsRecurring: " + currentCalendarItem.IsRecurring.ToString() + "\r\n";
                //sLines += "    IsMeeting: " + currentCalendarItem.IsMeeting.ToString() + "\r\n";
                //sLines += "    OriginalStart: " + currentCalendarItem.OriginalStart.ToString() + "\r\n";
                //sLines += "    HasAttachments: " + currentCalendarItem.HasAttachments.ToString() + "\r\n";
                //sLines += "    Attachments: " + "\r\n";

                // Note: You should not rely on the HasAttachments. 
                //  Please refer to: 
                //         Example: Returning a list of attachments using EWS
                //         http://blogs.msdn.com/webdav_101/archive/2009/01/05/example-returing-a-list-of-attachments-using-ews.aspx

                //Console.WriteLine("    xxxxxx  xxxxxx  xxxxxx  xxxxxx  xxxxxx");
                Console.WriteLine("");

                //sLines += "     \r\n  xxxxxx  xxxxxx  xxxxxx  xxxxxx  xxxxxx" + "\r\n";
                //sLines += "" + "\r\n";
            }
            Console.Read();

            //return sLines;

        }

        public static void SendMessage(string subject, string body, string toEmailAddress)
        {
            // Set the version, credentials, and the Client Access server on ExchangeServiceBinding.
            ExchangeServiceBinding esb = new ExchangeServiceBinding();
            esb.Credentials = new NetworkCredential("sebastian.renzi@southworks.net", "sebarenzi", "");
            esb.Url = "http://webmail.ihostexchange.net/ews/Exchange.asmx";

            // Create a CreateItem request object
            CreateItemType request = new CreateItemType();

            // Setup the request:
            // Indicate that we only want to send the message. No copy will be saved.
            request.MessageDisposition = MessageDispositionType.SendOnly;
            request.MessageDispositionSpecified = true;

            // Create a message object and set its properties
            MessageType message = new MessageType();
            message.Subject = subject;
            message.Body = new BodyType();
            message.Body.BodyType1 = BodyTypeType.Text;
            message.Body.Value = body;
            message.ToRecipients = new EmailAddressType[1];
            message.ToRecipients[0] = new EmailAddressType();
            message.ToRecipients[0].EmailAddress = toEmailAddress;
            message.ToRecipients[0].RoutingType = "SMTP";

            //There are some more properties in MessageType object 
            //you can set all according to your requirement
            // Construct the array of items to send
            request.Items = new NonEmptyArrayOfAllItemsType();
            request.Items.Items = new ItemType[1];
            request.Items.Items[0] = message;

            // Call the CreateItem EWS method.
            CreateItemResponseType response = esb.CreateItem(request);
            //this.ThrowOnError("SendMessage", response.ResponseMessages.Items[0]);
        }

        public static void GetContacts()
        {
            ExchangeServiceBinding esb = new ExchangeServiceBinding();
            esb.Credentials = new NetworkCredential("sebastian.renzi@southworks.net", "sebarenzi", "");
            esb.Url = "http://webmail.ihostexchange.net/ews/Exchange.asmx";

            // Tell it you want all the item properties
            ItemResponseShapeType itemProperties = new ItemResponseShapeType();
            itemProperties.BaseShape = DefaultShapeNamesType.AllProperties;

            // Tell it you only want to look in the contacts folder
            DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
            folderIDArray[0] = new DistinguishedFolderIdType();
            folderIDArray[0].Id = DistinguishedFolderIdNameType.contacts;

            ////PathToUnindexedFieldType field = new PathToUnindexedFieldType();
            ////field.FieldURI = UnindexedFieldURIType.contactsGivenName;

            ////ConstantValueType fieldValue = new ConstantValueType();
            ////fieldValue.Value = "";

            // Look for contacts which have a given name that begins with 'wes'
            ////ContainsExpressionType expr = new ContainsExpressionType();
            ////expr.ContainmentModeSpecified = true;
            ////expr.ContainmentMode = ContainmentModeType.Prefixed;
            ////expr.ContainmentComparisonSpecified = true;
            ////expr.ContainmentComparison = ContainmentComparisonType.IgnoreCase;
            ////expr.Constant = fieldValue;
            ////expr.Item = field;

            ////RestrictionType restriction = new RestrictionType();
            ////restriction.Item = expr;

            // Form the FindItem request
            FindItemType findItemRequest = new FindItemType();
            findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
            findItemRequest.ItemShape = itemProperties;
            findItemRequest.ParentFolderIds = folderIDArray;
            ////findItemRequest.Restriction = restriction;

            // Send the request and get the response
            FindItemResponseType findItemResponse = esb.FindItem(findItemRequest);

            if (findItemResponse.ResponseMessages.Items.Length > 0)
            {
                FindItemResponseMessageType responseMessage =
                    findItemResponse.ResponseMessages.Items[0] as FindItemResponseMessageType;
                ArrayOfRealItemsType realItems =
                    responseMessage.RootFolder.Item as ArrayOfRealItemsType;

                foreach (ContactItemType contact in realItems.Items)
                {
                    // Do work with data returned for each contact
                    Console.WriteLine("Name:  {0} {1}\nEmail: {2}\nPhone: {3}",
                        contact.GivenName, contact.Surname,
                        (contact.EmailAddresses != null && contact.EmailAddresses.Length > 0 ?
                            contact.EmailAddresses[0].Value : ""),
                        (contact.PhoneNumbers != null && contact.PhoneNumbers.Length > 0 ?
                            contact.PhoneNumbers[0].Value : ""));
                }
            }
        }

        public static void GetCalendar()
        {
            ExchangeServiceBinding esb = new ExchangeServiceBinding();
            esb.Credentials = new NetworkCredential("sebastian.renzi@southworks.net", "sebarenzi", "");
            esb.Url = "http://webmail.ihostexchange.net/ews/Exchange.asmx";

            // Tell it you want all the item properties
            ItemResponseShapeType itemProperties = new ItemResponseShapeType();
            itemProperties.BaseShape = DefaultShapeNamesType.AllProperties;

            // Tell it you only want to look in the calendar folder
            DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
            folderIDArray[0] = new DistinguishedFolderIdType();
            folderIDArray[0].Id = DistinguishedFolderIdNameType.calendar;

            ////PathToUnindexedFieldType field = new PathToUnindexedFieldType();
            ////field.FieldURI = UnindexedFieldURIType.contactsGivenName;

            ////ConstantValueType fieldValue = new ConstantValueType();
            ////fieldValue.Value = "";

            // Look for contacts which have a given name that begins with 'wes'
            ////ContainsExpressionType expr = new ContainsExpressionType();
            ////expr.ContainmentModeSpecified = true;
            ////expr.ContainmentMode = ContainmentModeType.Prefixed;
            ////expr.ContainmentComparisonSpecified = true;
            ////expr.ContainmentComparison = ContainmentComparisonType.IgnoreCase;
            ////expr.Constant = fieldValue;
            ////expr.Item = field;

            ////RestrictionType restriction = new RestrictionType();
            ////restriction.Item = expr;

            // Form the FindItem request
            FindItemType findItemRequest = new FindItemType();
            findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
            findItemRequest.ItemShape = itemProperties;
            findItemRequest.ParentFolderIds = folderIDArray;
            ////findItemRequest.Restriction = restriction;

            // Send the request and get the response
            FindItemResponseType findItemResponse = esb.FindItem(findItemRequest);

            if (findItemResponse.ResponseMessages.Items.Length > 0)
            {
                FindItemResponseMessageType responseMessage =
                    findItemResponse.ResponseMessages.Items[0] as FindItemResponseMessageType;
                ArrayOfRealItemsType realItems =
                    responseMessage.RootFolder.Item as ArrayOfRealItemsType;

                foreach (CalendarItemType calendar in realItems.Items)
                {
                    // Do work with data returned for each contact
                    Console.WriteLine("Description:  {0} \nStart: {1}\nEnd: {2}", calendar.Body, calendar.Start, calendar.End);
                }
            }
        }
    }
}
